package com.bbva.kyfb.kyfbdaofiimpl.pau;

import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.sql.Blob;
import java.util.Date;

import javax.sql.rowset.serial.SerialBlob;

import org.apache.commons.lang.StringUtils;

import com.bbva.jee.arq.spring.core.contexto.ArqSpringContext;
import com.bbva.jee.arq.spring.core.gce.ExcepcionEjecucionAplicacion;
import com.bbva.jee.arq.spring.core.log.I18nLog;
import com.bbva.jee.arq.spring.core.log.I18nLogFactory;
import com.bbva.jee.arq.spring.core.pau.AutenticacionBuilder;
import com.bbva.jee.arq.spring.core.pau.AutenticacionInmediata;
import com.bbva.jee.arq.spring.core.pau.Autenticador;
import com.bbva.jee.arq.spring.core.pau.exceptions.PauException;
import com.bbva.jee.arq.spring.core.pau.exceptions.PauRcException;
import com.bbva.jee.arq.spring.core.pau.utils.DatosAutenticacion;
import com.bbva.jee.arq.spring.core.pau.utils.DatosConexion;
import com.bbva.jee.arq.spring.core.pau.utils.ResultadoAutenticacion;
import com.bbva.kyfb.kyfbdto.firmas.bo.UsuarioInfo;
import com.bbva.kyfb.kyfbdto.firmas.errores.Errores_kyfb_servicios;
import com.bbva.kyfb.kyfbjpatlsb.dominiotlsb.Tbduefes;
import com.bbva.kyfb.kyfbjpatlsb.dominiotlsb.TbduefesPK;
import com.bbva.kyfb.kyfbutils.pau.ConstantesPAU;
import com.grupobbva.sl.an.pau.cliente.PAUCliente;
import com.grupobbva.sl.an.pau.cliente.PAUConexion;
import com.grupobbva.sl.an.pau.cliente.PAUSesion;
import com.grupobbva.sl.an.pau.comun.Constantes;

/**
 * The Class AutenticadorPAU.
 * 
 * @author usuario
 */
public class AutenticadorPAU {

	/** Variable LOG. */
	private static final I18nLog LOG = I18nLogFactory
			.getLogI18n(AutenticadorPAU.class);

	/** The autenticacion builder. */
	private AutenticacionBuilder autenticacionBuilder = null;

	/** The autenticador. */
	private Autenticador autenticador = null;

	/** The datos autenticacion. */
	private DatosAutenticacion datosAutenticacion = null;

	/** The autenticacion. */
	private ResultadoAutenticacion autenticacion = null;

	/** The datos conexion. */
	private DatosConexion datosConexion = null;

	/**
	 * Instantiates a new autenticador pau.
	 * 
	 * @param pauAplicacion
	 *            the pau aplicacion
	 * @param pauCanal
	 *            the pau canal
	 * @param pauOperacion
	 *            the pau operacion
	 * @param pauSec
	 *            the pau sec
	 * @param pauUser
	 *            the pau user
	 */
	public AutenticadorPAU(final String pauAplicacion, final String pauCanal,
			final String pauOperacion, final String pauSec, final String pauUser) {
		super();
		datosConexion = new DatosConexion(pauAplicacion, pauCanal,
				pauOperacion, pauSec, pauUser);
	}

	/**
	 * Instantiates a new autenticador pau.
	 */
	public AutenticadorPAU() {
		super();
		datosConexion = new DatosConexion();
	}

	/**
	 * comprobarFormulaOTP FTK01 Secuencia CA de Formula + Token de Vasco.
	 * 
	 * @param token
	 *            the token
	 * @param claveToken
	 *            the clave token
	 * @param resultadoFormula
	 *            the resultado formula
	 * @param numeroAleatorio
	 *            the numero aleatorio
	 * @return the string
	 */
	public String comprobarFormulaOTP(final String token,
			final String claveToken, final String resultadoFormula,
			final String numeroAleatorio) {
		String salida = Constantes.AUT_FALLO;
		try {
			datosAutenticacion = new DatosAutenticacion();
			datosAutenticacion.addPARAM1(token);
			datosAutenticacion.addPARAM2(claveToken);
			datosAutenticacion.addPARAM3(resultadoFormula);
			datosAutenticacion.addPARAM4(numeroAleatorio);
			datosAutenticacion.addPARAM5("");
			autenticacionBuilder = new AutenticacionInmediata();
			autenticador = new Autenticador(autenticacionBuilder);
			// conectamos con el servicio
			autenticador.conectar(datosConexion);
			autenticacion = autenticador.autenticar(datosAutenticacion);
			salida = autenticacion.getEstado();
		} catch (final PauException e) {
			LOG.error("AutenticadorPAU.comprobarFormulaOTP - No se puede conectar: "
					+ e.getMessage());
		} catch (final PauRcException e) {
			LOG.error("AutenticadorPAU.comprobarFormulaOTP - No se puede autenticar: "
					+ e.getMessage());
		}
		return salida;
	}

	/**
	 * validaClaveOperaciones CLO01 Secuencia de un solo paso con la CA de Clave
	 * de operaciones.
	 * 
	 * @param usuario
	 *            the usuario
	 * @param claveOperaciones
	 *            the clave operaciones
	 * @return the string
	 */
	public String validaClaveOperaciones(final String usuario,
			final String claveOperaciones) {
		String salida = Constantes.AUT_FALLO;
		try {
			datosAutenticacion = new DatosAutenticacion();
			datosAutenticacion.addPARAM1(usuario); // sCodUsuarioPAU
			datosAutenticacion.addPARAM2(claveOperaciones); // firmaPD
			datosAutenticacion.addPARAM3("");
			datosAutenticacion.addPARAM4("");
			datosAutenticacion.addPARAM5("");
			autenticacionBuilder = new AutenticacionInmediata();
			autenticador = new Autenticador(autenticacionBuilder);
			// conectamos con el servicio
			autenticador.conectar(datosConexion);
			autenticacion = autenticador.autenticar(datosAutenticacion);
			salida = autenticacion.getEstado();
		} catch (final PauException e) {
			LOG.error("AutenticadorPAU.validaClaveOperaciones - No se puede conectar: "
					+ e.getMessage());
		} catch (final PauRcException e) {
			LOG.error("AutenticadorPAU.validaClaveOperaciones - No se puede autenticar: "
					+ e.getMessage());
		}
		return salida;
	}

	/**
	 * validaClaveOperacionesVasco CTK01 Secuencia CA de Clave de Operaciones +
	 * Token de Vasco.
	 * 
	 * @param token
	 *            the token
	 * @param claveToken
	 *            the clave token
	 * @param usuario
	 *            the usuario
	 * @param claveOperaciones
	 *            the clave operaciones
	 * @return the string
	 */
	public String validaClaveOperacionesVasco(final String token,
			final String claveToken, final String usuario,
			final String claveOperaciones) {
		String salida = Constantes.AUT_FALLO;
		try {
			datosAutenticacion = new DatosAutenticacion();
			datosAutenticacion.addPARAM1(token);
			datosAutenticacion.addPARAM2(claveToken);
			datosAutenticacion.addPARAM3(usuario);
			datosAutenticacion.addPARAM4(claveOperaciones);
			datosAutenticacion.addPARAM5("");
			autenticacionBuilder = new AutenticacionInmediata();
			autenticador = new Autenticador(autenticacionBuilder);
			// conectamos con el servicio
			autenticador.conectar(datosConexion);
			autenticacion = autenticador.autenticar(datosAutenticacion);
			salida = autenticacion.getEstado();
		} catch (final PauException e) {
			LOG.error("AutenticadorPAU.validaClaveOperacionesVasco - No se puede conectar: "
					+ e.getMessage());
		} catch (final PauRcException e) {
			LOG.error("AutenticadorPAU.validaClaveOperacionesVasco - No se puede autenticar: "
					+ e.getMessage());
		}
		return salida;
	}

	/**
	 * validaFORMULA FRM01 Secuencia de un solo paso con la CA de Formula.
	 * 
	 * @param usuario
	 *            the usuario
	 * @param resultadoFormula
	 *            the resultado formula
	 * @param numeroAleatorio
	 *            the numero aleatorio
	 * @return the string
	 */
	public String validaFORMULA(final String usuario,
			final String resultadoFormula, final String numeroAleatorio) {
		String salida = Constantes.AUT_FALLO;
		try {
			datosAutenticacion = new DatosAutenticacion();
			datosAutenticacion.addPARAM1(usuario);
			datosAutenticacion.addPARAM2(resultadoFormula);
			datosAutenticacion.addPARAM3(numeroAleatorio);
			datosAutenticacion.addPARAM4("");
			datosAutenticacion.addPARAM5("");
			autenticacionBuilder = new AutenticacionInmediata();
			autenticador = new Autenticador(autenticacionBuilder);
			// conectamos con el servicio
			autenticador.conectar(datosConexion);
			autenticacion = autenticador.autenticar(datosAutenticacion);
			salida = autenticacion.getEstado();
		} catch (final PauException e) {
			LOG.error("AutenticadorPAU.validaFORMULA - No se puede conectar: "
					+ e.getMessage());
		} catch (final PauRcException e) {
			LOG.error("AutenticadorPAU.validaFORMULA - No se puede autenticar: "
					+ e.getMessage());
		}
		return salida;
	}

	/**
	 * enviaSesionOTP Envia el SMS correspondiente a la secuencia que se le
	 * pase.
	 * 
	 * @param telefono
	 *            the telefono
	 * @param mensaje
	 *            the mensaje
	 * @return PAUSesion
	 */
	public final PAUSesion enviaSesionOTP(final String telefono,
			final String mensaje) {
		String msj;
		PAUConexion conn;
		PAUSesion salida;
		try {
			// Comprobamos que no sea mock
			if (ArqSpringContext
					.getPropiedadBoolean(AutenticacionBuilder.PROPIEDAD_RUTA_MOCK_PAU)) {
				conn = PAUCliente.instanciaConexion();
				final PAUSesion sesion = conn.getNuevaSesion(
						datosConexion.getPauAplicacion(),
						datosConexion.getPauCanal(),
						datosConexion.getPauOperacion(),
						datosConexion.getPauUser(), datosConexion.getPauSec());
				sesion.setEstado("AUT_OK");
				salida = sesion;
			} else { // Si no es mock
				if (StringUtils.isBlank(mensaje)) {
					msj = ConstantesPAU.POSICION_CODIGO_OTP_SMS;
				} else if (mensaje.contains("%p")) {
					msj = mensaje;
				} else {
					msj = mensaje + "%p";
				}

				// Instanciamos la conexion
				conn = PAUCliente.instanciaConexion();
				// Creamos la sesion
				PAUSesion sesion = conn.getNuevaSesion(
						datosConexion.getPauAplicacion(),
						datosConexion.getPauCanal(),
						datosConexion.getPauOperacion(),
						datosConexion.getPauUser(), datosConexion.getPauSec());
				// Establecemos los parametros necesarios
				sesion.setDatoAdicional("PARAM1", telefono);
				sesion.setDatoAdicional("PARAM2", msj);
				// procesamos la peticion
				sesion = conn.procesaPeticion(sesion);

				salida = sesion;
			}
		} catch (final Exception e) {
			LOG.error("AutenticadorPAU.enviaSesionOTP - Error generico. No se puede enviar: "
					+ e.getMessage());
			salida = null;
		}
		return salida;
	}

	/**
	 * validaFORMULAOTP FOT01 Secuencia CA de Formula + OTP por SMS.
	 * 
	 * @param autenticator
	 *            the autenticator
	 * @param codigoSMS
	 *            the codigo sms
	 * @param resultadoFormula
	 *            the resultado formula
	 * @param numeroAleatorio
	 *            the numero aleatorio
	 * @return the string
	 */
	public String validaFORMULAOTP(final Autenticador autenticator,
			final String codigoSMS, final String resultadoFormula,
			final String numeroAleatorio) {
		String salida = Constantes.AUT_FALLO;
		try {
			datosAutenticacion = new DatosAutenticacion();
			datosAutenticacion.addPARAM1(codigoSMS);
			datosAutenticacion.addPARAM2(resultadoFormula);
			datosAutenticacion.addPARAM3(numeroAleatorio);
			datosAutenticacion.addPARAM4("");
			datosAutenticacion.addPARAM5("");
			// conectamos con el servicio
			autenticacion = autenticator.autenticar(datosAutenticacion);
			salida = autenticacion.getEstado();
		} catch (final PauException e) {
			LOG.error("AutenticadorPAU.validaFORMULAOTP - No se puede conectar: "
					+ e.getMessage());
		} catch (final Exception e) {
			LOG.error("AutenticadorPAU.validaFORMULAOTP - No se puede autenticar: "
					+ e.getMessage());
		}
		return salida;
	}

	/**
	 * validaFORMULAOTP FOT01 Secuencia CA de Formula + OTP por SMS Metodo
	 * sobrecargado para poder pasarle la sesion en lugar de el Autenticador.
	 * 
	 * @param sesion
	 *            the sesion
	 * @param codigoSMS
	 *            the codigo sms
	 * @param resultadoFormula
	 *            the resultado formula
	 * @param numeroAleatorio
	 *            the numero aleatorio
	 * @return the string
	 */
	public String validaFORMULAOTP(final PAUSesion sesion,
			final String codigoSMS, final String resultadoFormula,
			final String numeroAleatorio) {
		String salida = Constantes.AUT_FALLO;
		try {
			// Comprobamos que no sea mock
			if (ArqSpringContext
					.getPropiedadBoolean(AutenticacionBuilder.PROPIEDAD_RUTA_MOCK_PAU)) {
				salida = sesion.getEstado();
			} else { // Si es mock
				String error = "";
				final PAUConexion conn = PAUCliente.instanciaConexion();
				if (sesion.getEstado().equalsIgnoreCase(Constantes.AUT_SIG)) {
					sesion.setDatoAdicional("PARAM1", codigoSMS);
					sesion.setDatoAdicional("PARAM2", resultadoFormula);
					sesion.setDatoAdicional("PARAM3", numeroAleatorio);
				}
				final PAUSesion sesionTmp = conn.procesaPeticion(sesion);
				if (sesionTmp.getEstado().equals(Constantes.AUT_OK)) {
					error = Constantes.AUT_OK;
				} else {
					error = sesionTmp.getRc();
				}
				salida = error;
			}
		} catch (final Exception e) {
			LOG.error("AutenticadorPAU.validaFORMULAOTP - No se puede validar: "
					+ e.getMessage());
		}
		return salida;
	}

	/**
	 * validaCLOPSMS COT01 Secuencia CA de Clave de Operaciones + OTP por SMS.
	 * 
	 * @param autenticator
	 *            the autenticator
	 * @param codigoSMS
	 *            the codigo sms
	 * @param usuario
	 *            the usuario
	 * @param claveOperaciones
	 *            the clave operaciones
	 * @return the string
	 */
	public String validaCLOPSMS(final Autenticador autenticator,
			final String codigoSMS, final String usuario,
			final String claveOperaciones) {
		String salida = Constantes.AUT_FALLO;
		try {
			datosAutenticacion = new DatosAutenticacion();
			datosAutenticacion.addPARAM1(codigoSMS);
			datosAutenticacion.addPARAM2(usuario);
			datosAutenticacion.addPARAM3(claveOperaciones);
			datosAutenticacion.addPARAM4("");
			datosAutenticacion.addPARAM5("");

			autenticacion = autenticator.autenticar(datosAutenticacion);
			salida = autenticacion.getEstado();
		} catch (final PauException e) {
			LOG.error("AutenticadorPAU.validaCLOPSMS - No se puede conectar: "
					+ e.getMessage());
		} catch (final Exception e) {
			LOG.error("AutenticadorPAU.validaCLOPSMS - No se puede autenticar: "
					+ e.getMessage());
		}
		return salida;
	}

	/**
	 * validaCLOPSMS COT01 Secuencia CA de Clave de Operaciones + OTP por SMS
	 * Metodo sobrecargado para poder pasarle la sesion en lugar de el
	 * Autenticador.
	 * 
	 * @param sesion
	 *            the sesion
	 * @param codigoSMS
	 *            the codigo sms
	 * @param usuario
	 *            the usuario
	 * @param claveOperaciones
	 *            the clave operaciones
	 * @return the string
	 */
	public String validaCLOPSMS(final PAUSesion sesion, final String codigoSMS,
			final String usuario, final String claveOperaciones) {
		String salida = Constantes.AUT_FALLO;
		;
		try {
			// Comprobamos que no sea mock
			if (ArqSpringContext
					.getPropiedadBoolean(AutenticacionBuilder.PROPIEDAD_RUTA_MOCK_PAU)) {
				salida = sesion.getEstado();
			} else {
				String error = "";
				final PAUConexion conn = PAUCliente.instanciaConexion();
				if (sesion.getEstado().equalsIgnoreCase(Constantes.AUT_SIG)) {
					sesion.setDatoAdicional("PARAM1", codigoSMS);
					sesion.setDatoAdicional("PARAM2", usuario);
					sesion.setDatoAdicional("PARAM3", claveOperaciones);
				}
				final PAUSesion sesionTmp = conn.procesaPeticion(sesion);
				if (sesionTmp.getEstado().equals(Constantes.AUT_OK)) {
					error = Constantes.AUT_OK;
				} else {
					error = sesionTmp.getRc();
				}
				salida = error;
			}
		} catch (final Exception e) {
			LOG.error("AutenticadorPAU.validaCLOPSMS - No se puede validar: "
					+ e.getMessage());
		}
		return salida;
	}

	/**
	 * Metodo que devuelve la sesion (PAUSesion) accediendo a la base de datos
	 * según los datos del usuario y la sesion.
	 * 
	 * @param usuario
	 *            the usuario
	 * @param idSesion
	 *            the id sesion
	 * @return PAUSesion
	 */
	public PAUSesion devuelveSesion(final UsuarioInfo usuario,
			final String idSesion) {
		try {
			final TbduefesPK id = new TbduefesPK(Short.valueOf(usuario.getsCanal()),
					Short.valueOf(usuario.getsBancoInt()),
					usuario.getsReferencia(), Short.valueOf(usuario
							.getsBancoProducto()), Short.valueOf(usuario
									.getsProductoServicio()), Short.valueOf(usuario
											.getsCodSubProducto()), usuario.getsCodUsuario(),
											idSesion);
			LOG.info("AutenticadorPAU. DevuelveSesion: canal: "
					+ usuario.getsCanal() + " ,referencia: "
					+ usuario.getsReferencia() + " ,BancoProducto:"
					+ usuario.getsBancoProducto() + " ,ProductoServicio:"
					+ usuario.getsProductoServicio() + " ,CodSubProducto"
					+ usuario.getsCodSubProducto() + " ,CodUsuario"
					+ usuario.getsCodUsuario());
			final Tbduefes obj = Tbduefes.findTbduefes(id);

			final boolean objNull = obj == null;

			LOG.info("AutenticadorPAU. DevuelveSesion: es null Tbduesfes: " + objNull);
			if (!objNull){
				LOG.info("AutenticadorPAU. DevuelveSesion: sesion: "+(obj.getDesSesion() == null));
				LOG.info("AutenticadorPAU. DevuelveSesion: sesion2: "+ obj.getDesSesion().getClass());
				LOG.info("AutenticadorPAU. DevuelveSesion: sesion3: "+ obj.getDesSesion().toString());
				LOG.info("AutenticadorPAU. DevuelveSesion: desSesion:" + obj.getDesSesion().getBinaryStream());
			}
			final ObjectInputStream ois = new ObjectInputStream(obj.getDesSesion()
					.getBinaryStream());

			LOG.info("AutenticadorPAU. DevuelveSesion: ois:" + (ois == null));

			final Object sesionAux = ois.readObject();
			LOG.info("AutenticadorPAU. DevuelveSesion: crearPAUSesion ");
			final PAUSesion sesion = (PAUSesion) sesionAux;
			ois.close();
			return sesion;
		} catch (final Exception e) {
			LOG.info("AutenticadorPAU. DevuelveSesion: excepcion " + e.getMessage());
			throw new ExcepcionEjecucionAplicacion(
					Errores_kyfb_servicios.ERROR_BBDD, e);
		}
	}

	/**
	 * Metodo para guardar la sesion creada por el usuario en la bbdd. Se guarda
	 * en la tabla BDUE.TBDUEFES
	 * 
	 * @param usuario
	 *            the usuario
	 * @param sesion
	 *            the sesion
	 * @param audUsuario
	 *            the aud usuario
	 * @return the string
	 */
	public String guardarSesion(final UsuarioInfo usuario,
			final PAUSesion sesion, final String audUsuario) {
		try {
			final TbduefesPK id = new TbduefesPK(Short.valueOf(usuario.getsCanal()),
					Short.valueOf(usuario.getsBancoInt()),
					usuario.getsReferencia(), Short.valueOf(usuario
							.getsBancoProducto()), Short.valueOf(usuario
									.getsProductoServicio()), Short.valueOf(usuario
											.getsCodSubProducto()), usuario.getsCodUsuario(),
											sesion.getIdSesion());
			final Tbduefes fes = new Tbduefes();
			fes.setId(id);
			fes.setXtiTipenv2(ConstantesPAU.XTI_TIPENV2);
			fes.setEstEstadenv(Short.valueOf("0"));
			fes.setFecEnviosms(new Date());
			fes.setTimEnviosms(new Date());
			fes.setAudUsuario(audUsuario);
			fes.setAudFmodific(new Date());
			// Convertimos la sesion a Blob para poder guardarla
			final ByteArrayOutputStream baos = new ByteArrayOutputStream();
			final ObjectOutputStream oos = new ObjectOutputStream(baos);
			oos.writeObject(sesion);
			final byte[] sesionAsBytes = baos.toByteArray();
			final Blob desSesion = new SerialBlob(sesionAsBytes);
			// Guardamos como Blob la sesion
			fes.setDesSesion(desSesion);
			// Cerramos conexiones de transformacion
			oos.flush();
			oos.close();
			baos.close();
			fes.setDesServpau(ConstantesPAU.DES_SERVPAU);
			// Persistimos
			fes.persist();
			// fes.flush();
			return sesion.getIdSesion();
		} catch (final Exception e) {
			throw new ExcepcionEjecucionAplicacion(
					Errores_kyfb_servicios.ERROR_BBDD, e);
		}
	}
}
